/*
 * $Id: zycl.cpp 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
 *
 * Copyright (c) 2006, 2007, 2008 Prabhu Gurumurthy <pgurumur@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <zypp/ZYppFactory.h>
#include <zypp/PathInfo.h>
#include <zypp/Capability.h>
#include <zypp/sat/Solvable.h>
#include <zypp/sat/WhatProvides.h>
#include <zypp/base/LogTools.h>
#include <zypp/base/LogControl.h>
#include <zypp/ResKind.h>
#include <zypp/PoolQuery.h>

#include "zycl.h"

namespace zycl {
   zycl::zycl(Tcl_Interp *interp, int32_t &argc, Tcl_Obj *const *argv) :
      _interp(interp), _argc(argc)
   {
      zypp::Pathname sysRoot("/");
      _zyclptr = zypp::ZYppFactory::instance().getZYpp();
      _zyclptr->initializeTarget(sysRoot, false);
      _zyclptr->target()->load();
      _program = tostring(argv[0]);
   }
   
   zycl::zycl(const zycl &Zycl)
   {
      *this = Zycl;
   }

   zycl& zycl::operator= (const zycl &Zycl)
   {
      zypp::Pathname sysRoot("/");
      _interp = Zycl._interp;
      _program = Zycl._program;
      _zyclptr = Zycl._zyclptr;
      _zyclptr->initializeTarget(sysRoot, false);
      _zyclptr->target()->load();
      _argc = Zycl._argc;

      return *this;
   }

   zycl::~zycl()
   {
      _argc = 0;
      _program = '\0';
      _interp = NULL;
   }

   int zycl::length() const
   {
      return _argc;
   }

   std::string zycl::tostring(Tcl_Obj *argv)
   {
      int length = 0;
      std::string retval = Tcl_GetStringFromObj(argv, &length);

      return retval;
   }

   void zycl::help()
   {
      std::cout << _program << " commands [ packages ] " << std::endl;
      std::cout << "commands: " << std::endl;
      std::cout << "\t what-provides (wp)" << std::endl;
      std::cout << "\t search (srch)" << std::endl;
      std::cout << "\t help (h)" << std::endl;
   }

   int zycl::provides(std::string &arg)
   {
      zypp::Capability cap(zypp::Capability::guessPackageSpec(arg));
      zypp::sat::WhatProvides wp(cap);

      std::string out;
      if (wp.empty()) {
         out += "No providers of " + arg + " found ";
      }
      else {
         for_(it, wp.begin(), wp.end()) {
            zypp::sat::Solvable package(*it);
            out += package.name() + " " + package.edition().version() + " " + 
               package.vendor().asString() + " " + 
               package.arch().asString()  + " " + package.asString();
         }
      }

      Tcl_SetObjResult(_interp, Tcl_NewStringObj(out.c_str(), -1));
      return TCL_OK;
   }

   void zycl::_addItemToList(
         Tcl_Interp *interp, Tcl_Obj *list, std::string &item)
   {
      if (item.length()) {
         Tcl_Obj *packstr = Tcl_NewStringObj(item.c_str(), item.length());
         Tcl_IncrRefCount(packstr);
         Tcl_ListObjAppendElement(interp, list, packstr);
         Tcl_DecrRefCount(packstr);
      }
   }

   int zycl::search(std::string &arg)
   {
      int retval = TCL_ERROR;
      if (arg.length()) {
         zypp::PoolQuery query;
         query.setMatchWord();
         query.addKind(zypp::ResKind::package);
         query.addString(arg);
         Tcl_Obj *list = Tcl_NewListObj(0, NULL);
         if (query.size() > 0) {
            for_(it, query.begin(), query.end()) {
               std::string out;
               zypp::sat::Solvable package(*it);
               out += package.name() + " " + package.edition().version() +
                  " " + package.vendor().asString() + " " + 
                  package.arch().asString()  + " " + package.asString();
               _addItemToList(_interp, list, out);
            }
         }

         Tcl_SetObjResult(_interp, list);
         retval = TCL_OK;
      }

      return retval;
   }
}

